package systems.particles 
{
	import flash.geom.PerspectiveProjection;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.Utils3D;
	import flash.geom.Vector3D;
	/**
	 * @author Nicolas Barradeau
	 * http://en.nicoptere.net
	 */
	public class Renderer3D
	{
		
		static private var perspective:PerspectiveProjection = new PerspectiveProjection();
		static private var matrix:Matrix3D = new Matrix3D();
		static private var vertices2D:Vector.<Number> = new Vector.<Number>();
		
		static public var objectRotation:Vector3D = new Vector3D( 0,0,0 );
		static public var cameraPosition:Vector3D = new Vector3D( 0,0,500 );
		static public var uvt:Vector.<Number> = new Vector.<Number>();
		
		static public var focal:Number = 500;
		
		static public var minZ:Number = Number.POSITIVE_INFINITY;
		static public var maxZ:Number = Number.NEGATIVE_INFINITY;
		
		public function Renderer3D(){}
		
		public static function projectVectors( vectors:Vector.<Vector3D>, center:Point = null, processZbounds:Boolean = true ):Vector.<Number>
		{
			var vertices:Vector.<Number> = Vector.<Number>([]);
			for each( var v:Vector3D in vectors )
			{
				vertices.push( v.x, v.y, v.z );
			}
			return project( vertices, center, processZbounds );
		}
		
		public static function project( vertices3D:Vector.<Number>, center:Point = null, processZbounds:Boolean = true ):Vector.<Number>
		{
			
			vertices2D = new Vector.<Number>();
			uvt = new Vector.<Number>();
			
			cameraPosition.z = ( cameraPosition.z < 100 ) ? 100 : cameraPosition.z;
			
			perspective.focalLength = focal;
			if ( center != null ) perspective.projectionCenter = center;
			
			matrix.identity();
			
			matrix.prependRotation( objectRotation.x, Vector3D.X_AXIS);
			matrix.prependRotation( objectRotation.y, Vector3D.Y_AXIS);
			matrix.prependRotation( objectRotation.z, Vector3D.Z_AXIS);
			
			matrix.appendTranslation( cameraPosition.x, cameraPosition.y, cameraPosition.z );
			matrix.append( perspective.toMatrix3D() );
			
			
			Utils3D.projectVectors( matrix, vertices3D, vertices2D, uvt );
			
			if ( processZbounds )
			{
				var i:int;
				var _z:Number;
				minZ = Number.POSITIVE_INFINITY;
				maxZ = Number.NEGATIVE_INFINITY;
				for ( i = 0; i < uvt.length; i+=3 )
				{
					
					_z = uvt[ i+2 ];
					if ( minZ > _z ) minZ = _z;
					if ( maxZ < _z ) maxZ = _z;
					
				}
				maxZ -= minZ;
			}
			return vertices2D;
			
		}
		
		public static function transform( vertices3D:Vector.<Number> ):Vector.<Number>
		{
			
			var transform:Vector.<Number> = new Vector.<Number>();
			
			cameraPosition.z = ( cameraPosition.z < 100 ) ? 100 : cameraPosition.z;
			
			perspective.focalLength = 500;
			
			matrix.identity();
			
			matrix.prependRotation( objectRotation.x, Vector3D.X_AXIS);
			matrix.prependRotation( objectRotation.y, Vector3D.Y_AXIS);
			matrix.prependRotation( objectRotation.z, Vector3D.Z_AXIS);
			
			matrix.prependTranslation( cameraPosition.x, cameraPosition.y, cameraPosition.z );
			matrix.transformVectors( vertices3D, transform );
			
			//trace( vertices3D.length, transform.length );
			//trace( vertices3D );
			//trace('--------------' );
			//trace( transform );
			return transform;
		}
	}

}